﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DevTest.Config
{
    public class DTUConfigItem
    {
        /// <summary>
        /// 是否发送
        /// </summary>
        public bool Enable { get; set; } = true;



        /// <summary>
        /// 是否数字
        /// </summary>
        public int IsNumeric { get; set; }


        /// <summary>
        /// 配置代码
        /// </summary>
        public byte Code { get; set; }

        /// <summary>
        /// 配置名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 配置说明
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 配置值的字节数
        /// </summary>
        public int ValueBytesCount { get; set; }


        private object _value;
        /// <summary>
        /// 配置值
        /// </summary>
        public object ConfigValue
        {
            get =>  _value;
            set{
                if (_value == value) return;
                 _value = value;
                Build();
            }
        }

        public void Parse(byte[] data,int offset,int length)
        {

            if (IsNumeric == 1)
            {

                int v = (data[offset + 0] << 8) + data[offset + 1];
                ConfigValue = v;

            }
            else
            {

                ConfigValue = ASCIIEncoding.ASCII.GetString(data, offset, length);
            }




        }


        /// <summary>
        /// 配置值的字节数据
        /// </summary>
        public byte[] ConfigBytes { get;private set; }

        public void Build()
        {
            byte[] data = null;
            if (IsNumeric == 1)
            {
                data = new byte[2];
                short shortvalue =Convert.ToInt16( ConfigValue);
                data[0] = (byte)(shortvalue >> 8);
                data[1] = (byte)shortvalue;

            }
            else
            {
                string str = (string)ConfigValue;
                data= ASCIIEncoding.ASCII.GetBytes(str); 
            }

            ConfigBytes = new byte[2 + data.Length];
            ConfigBytes[0] = (byte)data.Length;
            ConfigBytes[1] = (byte)Code;
            Buffer.BlockCopy(data, 0, ConfigBytes, 2, data.Length);

        }


    }


    public class DTUConfigManager
    {
        public List<DTUConfigItem> _Configs = new List<DTUConfigItem>();

        string _ConfigFilePath = "";


        private static FileSystemWatcher m_Watcher;

        private static DateTime m_LastUpdatedTime;

        public List<DTUConfigItem> Configs
        {
            get
            {
                return _Configs;
            } 
        }
        /// <summary>
        /// Watches the specified configuration section.
        /// </summary>
        /// <param name="configSection">The configuration section.</param>
        /// <param name="bootstrap">The bootstrap.</param>
        public void Watch()
        {



            var configSourceFile = _ConfigFilePath;

            if (string.IsNullOrEmpty(configSourceFile))
                throw new Exception("没找到配置文件");

            m_Watcher = new FileSystemWatcher(Path.GetDirectoryName(configSourceFile), Path.GetFileName(configSourceFile));
            m_Watcher.IncludeSubdirectories = false;
            m_Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
            m_Watcher.Changed += (s, e) =>
            {
                var filePath = e.FullPath;

                 

                Task.Factory.StartNew(() => {
                    Thread.Sleep(1000);
                    LoadConfig(_ConfigFilePath);
                });

            };

            m_Watcher.EnableRaisingEvents = true;
        }
        public void ParseConfigPackage(byte[] data)
        {
            int offset = 0;
            while (offset < data.Length)
            {
                int len = data[offset];
                offset++;
                byte code = data[offset];
                offset++;
                _Configs.Single(c => c.Code == code).Parse(data, offset, len);
                offset += len;
            } 
        }

        public byte[] GetConfigPackage()
        {
            var configs= _Configs.Where(c => c.Enable);
            int packageLength = configs.Sum(c => c.ConfigBytes.Length);
            byte[] packageData =new byte[packageLength];
            int offset = 0;
            foreach (var item in configs)
            {
                Buffer.BlockCopy(item.ConfigBytes, 0, packageData, offset, item.ConfigBytes.Length);
                offset += item.ConfigBytes.Length;
            }

            return packageData;
            
        }

        void LoadConfig(string configpath)
        {

            StreamReader sr = new StreamReader(configpath);

            //跳过首行
            sr.ReadLine();
            string line;

            char[] sep = new char[] { '\t' };
            _Configs.Clear();
            while (!string.IsNullOrEmpty(line = sr.ReadLine()))
            {
                //读取第i组

                string[] cfgline = line.Split(sep, StringSplitOptions.RemoveEmptyEntries);
                var cfg = new DTUConfigItem()
                {
                    IsNumeric = int.Parse(cfgline[0]),
                    Enable = cfgline[1] == "1" ? true : false,
                    Code = byte.Parse(cfgline[2]),
                    Name = cfgline[3],
                    Description = cfgline[4],
                };

                if (cfg.IsNumeric == 1)
                    cfg.ConfigValue = int.Parse(cfgline[5]);
                else
                    cfg.ConfigValue = cfgline[5];

                _Configs.Add(cfg);
            }
            sr.Close();

        }


        public DTUConfigManager(string configpath = "")
        {
           _ConfigFilePath=  AppDomain.CurrentDomain.BaseDirectory + "DTUConfig.txt";

            if (string.IsNullOrEmpty(configpath))
            {
               
                configpath = _ConfigFilePath;
            }
            else
            {
                _ConfigFilePath = configpath;

            }


            LoadConfig(configpath);

            Watch();
        }


    }
}
